/*
 * Copyright (c) 2021 Futurewei Technologies, Inc.
 *
 * clang2mpl is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2. You may obtain a copy of Mulan PSL v2 at:
 *
 *     http://license.coscl.org.cn/MulanPSL2
 *
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. See the
 * Mulan PSL v2 for more details.
 */
// RUN: %clang2mpl --ascii --verify %s -- -Wno-unused-value
// --target=aarch64-linux-elf RUN: cat %m | %FileCheck %s

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>

// CHECK: [[# FILENUM:]] "{{.*}}/test/intrinsics.c"

struct S {
  int a;
  int b;
};

int g;

void foo() {
  int i;
  long l;
  long long ll;
  unsigned long ul;
  float f;
  double d;
  long double ld;
  char *s;
  struct S sS;
  const int c = 42;

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs i32 (dread i32 %i)
  abs(i);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs i32 (dread i32 %i)
  __builtin_abs(i);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs i64 (dread i64 %l)
  labs(l);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs i64 (dread i64 %l)
  __builtin_labs(l);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs i64 (dread i64 %ll)
  llabs(ll);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs i64 (dread i64 %ll)
  __builtin_llabs(ll);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs f64 (dread f64 %d)
  fabs(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs f64 (dread f64 %d)
  __builtin_fabs(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs f32 (dread f32 %f)
  fabsf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs f32 (dread f32 %f)
  __builtin_fabsf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs f64 (dread f64 %ld)
  fabsl(ld);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: abs f64 (dread f64 %ld)
  __builtin_fabsl(ld);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_acos (dread f64 %d))
  __builtin_acos(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_acos (dread f64 %d))
  acos(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_acosf (dread f32 %f))
  __builtin_acosf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_acosf (dread f32 %f))
  acosf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: alloca a64 (constval u64 4))
  alloca(4);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: alloca a64 (constval u64 16))
  __builtin_alloca(16);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_asin (dread f64 %d))
  __builtin_asin(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_asin (dread f64 %d))
  asin(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_asinf (dread f32 %f))
  __builtin_asinf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_asinf (dread f32 %f))
  asinf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_atan (dread f64 %d))
  __builtin_atan(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_atan (dread f64 %d))
  atan(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_atanf (dread f32 %f))
  __builtin_atanf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_atanf (dread f32 %f))
  atanf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 1
  __builtin_classify_type(i);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 8
  __builtin_classify_type(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 5
  __builtin_classify_type(s);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 12
  __builtin_classify_type(sS);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_cos (dread f64 %d))
  __builtin_cos(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_cos (dread f64 %d))
  cos(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_cosf (dread f32 %f))
  __builtin_cosf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_cosf (dread f32 %f))
  cosf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_cosh (dread f64 %d))
  __builtin_cosh(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_cosh (dread f64 %d))
  cosh(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_coshf (dread f32 %f))
  __builtin_coshf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_coshf (dread f32 %f))
  coshf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop i32 C_clz32 (cvt u32 i32 (dread i32 %i))
  __builtin_clz(i);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop i32 C_clz64 (cvt u64 i64 (dread i64 %l))
  __builtin_clzl(l);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop i32 C_clz64 (cvt u64 i64 (dread i64 %ll))
  __builtin_clzll(ll);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 1
  __builtin_constant_p(3 + 4);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 1
  __builtin_constant_p(c);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 0
  __builtin_constant_p(&g);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval i32 0
  __builtin_constant_p(ll * i);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop i32 C_ctz32 (cvt u32 i32 (dread i32 %i))
  __builtin_ctz(i);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop i32 C_ctz64 (cvt u64 i64 (dread i64 %l))
  __builtin_ctzl(l);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop i32 C_ctz64 (cvt u64 i64 (dread i64 %ll))
  __builtin_ctzll(ll);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_exp (dread f64 %d))
  __builtin_exp(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_exp (dread f64 %d))
  exp(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_expf (dread f32 %f))
  __builtin_expf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_expf (dread f32 %f))
  expf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: add i64 (dread i64 %l, dread i64 %l)
  __builtin_expect(l + l, 0);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop i32 C_ffs (dread i32 %i))
  __builtin_ffs(i);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: max f64 (dread f64 %d, dread f64 %d)
  fmax(d, d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: max f64 (dread f64 %d, dread f64 %d)
  __builtin_fmax(d, d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: max f32 (dread f32 %f, dread f32 %f)
  fmaxf(f, f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: max f32 (dread f32 %f, dread f32 %f)
  __builtin_fmaxf(f, f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: max f64 (dread f64 %ld, dread f64 %ld)
  fmaxl(ld, ld);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: max f64 (dread f64 %ld, dread f64 %ld)
  __builtin_fmaxl(ld, ld);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: min f64 (dread f64 %d, dread f64 %d)
  fmin(d, d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: min f64 (dread f64 %d, dread f64 %d)
  __builtin_fmin(d, d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: min f32 (dread f32 %f, dread f32 %f)
  fminf(f, f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: min f32 (dread f32 %f, dread f32 %f)
  __builtin_fminf(f, f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: min f64 (dread f64 %ld, dread f64 %ld)
  fminl(ld, ld);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: min f64 (dread f64 %ld, dread f64 %ld)
  __builtin_fminl(ld, ld);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: call &__isinf (dread f64 %d)
  __builtin_isinf_sign(d);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval f64 inf
  __builtin_huge_val();
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval f64 inf
  __builtin_inf();
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval f32 inf
  __builtin_huge_valf();
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: constval f32 inf
  __builtin_inff();

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_log (dread f64 %d))
  __builtin_log(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_log (dread f64 %d))
  log(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_logf (dread f32 %f))
  __builtin_logf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_logf (dread f32 %f))
  logf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_log10 (dread f64 %d))
  __builtin_log10(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_log10 (dread f64 %d))
  log10(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_log10f (dread f32 %f))
  __builtin_log10f(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_log10f (dread f32 %f))
  log10f(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_memcmp (dread a64 %s, dread a64 %s, dread u64 %ul)
  memcmp(s, s, ul);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_memcmp (dread a64 %s, dread a64 %s, dread u64 %ul)
  __builtin_memcmp(s, s, ul);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_memcpy (dread a64 %s, dread a64 %s, dread u64 %ul)
  memcpy(s, s, ul);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_memcpy (dread a64 %s, dread a64 %s, dread u64 %ul)
  __builtin_memcpy(s, s, ul);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_memmove (dread a64 %s, dread a64 %s, dread u64 %ul)
  memmove(s, s, ul);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_memmove (dread a64 %s, dread a64 %s, dread u64 %ul)
  __builtin_memmove(s, s, ul);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_memset (dread a64 %s, dread i32 %i, dread u64 %ul)
  memset(s, i, ul);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_memset (dread a64 %s, dread i32 %i, dread u64 %ul)
  __builtin_memset(s, i, ul);

  // This doesn't generate any code for now, so nothing to check for, just make
  // sure it doesn't get any errors.
  __builtin_prefetch(s);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: call &__signbit (dread f64 %d)
  __builtin_signbit(d);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_sin (dread f64 %d))
  __builtin_sin(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_sin (dread f64 %d))
  sin(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_sinf (dread f32 %f))
  __builtin_sinf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_sinf (dread f32 %f))
  sinf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_sinh (dread f64 %d))
  __builtin_sinh(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f64 C_sinh (dread f64 %d))
  sinh(d);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_sinhf (dread f32 %f))
  __builtin_sinhf(f);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsicop f32 C_sinhf (dread f32 %f))
  sinhf(f);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_strcmp (dread a64 %s, dread a64 %s)
  strcmp(s, s);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_strcmp (dread a64 %s, dread a64 %s)
  __builtin_strcmp(s, s);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_strncmp (dread a64 %s, dread a64 %s, dread u64 %ul)
  strncmp(s, s, ul);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_strncmp (dread a64 %s, dread a64 %s, dread u64 %ul)
  __builtin_strncmp(s, s, ul);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_strcpy (dread a64 %s, dread a64 %s)
  strcpy(s, s);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_strcpy (dread a64 %s, dread a64 %s)
  __builtin_strcpy(s, s);

  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_strncpy (dread a64 %s, dread a64 %s, dread u64 %ul)
  strncpy(s, s, ul);
  // CHECK: LOC [[# FILENUM]] [[# @LINE + 2 ]]{{$}}
  // CHECK-NEXT: intrinsiccall C_strncpy (dread a64 %s, dread a64 %s, dread u64 %ul)
  __builtin_strncpy(s, s, ul);


}
